home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 August: Tool Chest / Dev.CD Aug 00 TC Disk 2.toast / pc / sample code / quicktime / music and sound / qt qdesign decomp / source / qdesign_decomp.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-06-23  |  15.4 KB  |  572 lines

  1. /*
  2. **    Apple Macintosh Developer Technical Support
  3. **
  4. **    Routines demonstrating how to play QDesign compressed AIFF files
  5. **    using a combination of QuickTime and the Sound Manager.
  6. **
  7. **    by Mark Cookson, Apple Developer Technical Support
  8. **
  9. **    File:    QDesign_decomp.c
  10. **
  11. **    Copyright ©1998-1999 Apple Computer, Inc.
  12. **    All rights reserved.
  13. **
  14. **    You may incorporate this sample code into your applications without
  15. **    restriction, though the sample code has been provided "AS IS" and the
  16. **    responsibility for its operation is 100% yours.  However, what you are
  17. **    not permitted to do is to redistribute the source as "Apple Sample
  18. **    Code" after having made changes. If you're going to re-distribute the
  19. **    source, we require that you make it clear in the source that the code
  20. **    was descended from Apple Sample Code, but that you've made changes.
  21. */
  22.  
  23. #include <Memory.h>
  24. #include <QuickDraw.h>
  25. #include <Fonts.h>
  26. #include <Windows.h>
  27. #include <Menus.h>
  28. #include <TextEdit.h>
  29. #include <Dialogs.h>
  30. #include <Sound.h>
  31. #include <SoundInput.h>
  32. #include <Files.h>
  33. #include <Navigation.h>
  34.  
  35. #include <stdio.h>
  36. #include "SoundStruct.h"
  37. #include "AIFF.h"
  38.  
  39. typedef struct {
  40.     long            atomSize;            // how big this structure is (big endian)
  41.     long            atomType;            // atom type
  42.     char            waveData[28];
  43. } AtomQDMCWaveFormatEx;
  44.  
  45. typedef struct {
  46.     AudioFormatAtom                formatData;
  47.     AtomQDMCWaveFormatEx        endianData;
  48.     AudioTerminatorAtom            terminatorData;
  49. } AudioCompressionAtom, *AudioCompressionAtomPtr, **AudioCompressionAtomHandle;
  50.  
  51. // Prototypes
  52. OSErr InstallRequiredAppleEvents (void);
  53. pascal OSErr HandleOApp (AppleEvent *theAppleEvent, AppleEvent *reply, long handlerRefcon);
  54. pascal OSErr HandleODoc (AppleEvent *theAppleEvent, AppleEvent *reply, long handlerRefcon);
  55. pascal OSErr HandlePDoc (AppleEvent *theAppleEvent, AppleEvent *reply, long handlerRefcon);
  56. pascal OSErr HandleQuit (AppleEvent *theAppleEvent, AppleEvent *reply, long handlerRefcon);
  57. OSErr GetSoundToPlay (FSSpec *fileToPlay);
  58. OSErr PlaySound (FSSpec *fileToPlay);
  59.  
  60. // Globals
  61. Boolean                gBufferDone        = false,
  62.                     gDone            = false;
  63.  
  64. static pascal void    SoundCallBackFcn (SndChannelPtr theChannel, SndCommand *theCmd) {
  65. #pragma unused (theChannel)
  66.     #if !GENERATINGCFM
  67.         long        oldA5;
  68.         oldA5 = SetA5 (theCmd->param2);
  69.     #endif
  70.  
  71.     gBufferDone = true;
  72.  
  73.     #if !GENERATINGCFM
  74.         oldA5 = SetA5 (oldA5);
  75.     #endif
  76. }
  77.  
  78. static OSErr MenuBarInit (void) {
  79.     Handle                    menuBar;
  80.     MenuHandle                menu;
  81.     OSErr                    err                = noErr;
  82.  
  83.     menuBar = GetNewMBar (128);
  84.     if (menuBar != nil) {
  85.         SetMenuBar (menuBar);
  86.         menu = GetMenuHandle (128);
  87.         if (menu != nil) {
  88.             AppendResMenu (menu, 'DRVR');
  89.             DrawMenuBar ();
  90.         } else {
  91.             err = memFullErr;
  92.         }
  93.     } else {
  94.         err = memFullErr;
  95.     }
  96.  
  97.     return err;
  98. }
  99.  
  100. static OSErr DispatchMenuChoice (long menuChoice) {
  101.     OSErr                        err                    = noErr;
  102.     short                        menu;
  103.     short                        item;
  104.     MenuHandle                    appleMenu;
  105.     Str255                        accName;
  106.     short                        accNumber;
  107.     FSSpec                        fileToPlay;
  108.  
  109.     if (menuChoice != 0) {
  110.         menu = HiWord (menuChoice);
  111.         item = LoWord (menuChoice);
  112.         switch (menu) {
  113.             case 128:    // Apple Menu
  114.                 appleMenu = GetMenuHandle (128);
  115.                 GetMenuItemText (appleMenu, item, accName);
  116.                 accNumber = OpenDeskAcc (accName);
  117.                 break;
  118.             case 129:    // File Menu
  119.                 switch (item) {
  120.                     case 1:    // Open
  121.                         err = GetSoundToPlay (&fileToPlay);
  122.                         break;
  123.                     case 3:    // Quit
  124.                         gDone = true;
  125.                         break;
  126.                 }
  127.         }
  128.     }
  129.  
  130.     HiliteMenu (0);
  131.  
  132.     return err;
  133. }
  134.  
  135. void main (void) {
  136.     OSErr                        err                    = noErr;
  137.     Boolean                        gotEvent;
  138.     EventRecord                    event;
  139.     WindowPtr                    window;
  140.     short                        thePart;
  141.  
  142.     MaxApplZone ();
  143.  
  144.     InitGraf (&qd.thePort);
  145.     InitFonts ();
  146.     InitWindows ();
  147.     InitMenus ();
  148.     TEInit ();
  149.     InitDialogs ((long)nil);
  150.     InitCursor ();
  151.  
  152.     err = InstallRequiredAppleEvents ();
  153.  
  154.     err = MenuBarInit ();
  155.  
  156.     while (!gDone) {
  157.         gotEvent = WaitNextEvent (everyEvent, &event, 10, nil);
  158.  
  159.         if (gotEvent) {
  160.             switch (event.what) {
  161.                 case kHighLevelEvent:
  162.                     err = AEProcessAppleEvent (&event);
  163.                     break;
  164.                 case mouseDown:
  165.                     thePart = FindWindow (event.where, &window);
  166.                     switch (thePart) {
  167.                         case inMenuBar:
  168.                             DispatchMenuChoice (MenuSelect (event.where));
  169.                             break;
  170.                     }
  171.                     break;
  172.                 case keyDown:
  173.                     if (event.modifiers & cmdKey) {
  174.                         err = DispatchMenuChoice (MenuKey (event.message & charCodeMask));
  175.                     }
  176.                     break;
  177.             }
  178.         }
  179.     }
  180. }
  181.  
  182. OSErr GetSoundToPlay (FSSpec *fileToPlay) {
  183.     OSErr                    err                    = noErr;
  184.     SFTypeList                typeList            = {'AIFF', 'AIFC', 0, 0};
  185.     StandardFileReply        sfReply;
  186.  
  187.     if (NavServicesAvailable () == true) {
  188.         NavReplyRecord                navReply;
  189.         NavDialogOptions            dialogOptions;
  190.  
  191.         err = NavGetDefaultDialogOptions (&dialogOptions);
  192.         if (err == noErr) {
  193.             dialogOptions.dialogOptionFlags = kNavAllFilesInPopup;
  194.         }
  195.  
  196.         if (err == noErr) {
  197.             err = NavGetFile (nil, &navReply, &dialogOptions, nil, nil, nil, nil, nil);
  198.         }
  199.  
  200.         if (navReply.validRecord && err == noErr) {
  201.             ProcessSerialNumber            processSN        = {0, kCurrentProcess};
  202.             AEAddressDesc                targetAddress    = {typeNull, nil};
  203.             AppleEvent                    theODOC            = {typeNull, nil},
  204.                                         theReply        = {typeNull, nil};
  205.  
  206.             // Create an Apple Event to ourselves.
  207.             err = AECreateDesc (typeProcessSerialNumber, &processSN, sizeof (ProcessSerialNumber), &targetAddress);
  208.  
  209.             if (err == noErr) {
  210.                 // Create the open document event.
  211.                 err = AECreateAppleEvent (kCoreEventClass, kAEOpenDocuments, &targetAddress, kAutoGenerateReturnID, kAnyTransactionID, &theODOC);
  212.                 AEDisposeDesc (&targetAddress);
  213.             }
  214.  
  215.             if (err == noErr) {
  216.                 // Put the list of files into the open document event Apple Event.
  217.                 err = AEPutParamDesc (&theODOC, keyDirectObject, &(navReply.selection));
  218.             }
  219.  
  220.             if (err == noErr) {
  221.                 // Send the open document event to ourselves.
  222.                 err = AESend (&theODOC, &theReply, kAENoReply, kAENormalPriority, kAEDefaultTimeout, nil, nil);
  223.                 AEDisposeDesc (&theODOC);
  224.                 AEDisposeDesc (&theReply);
  225.             }
  226.  
  227.         }
  228.  
  229.         (void)NavDisposeReply (&navReply);
  230.     } else {
  231.         StandardGetFile (nil, 2, typeList, &sfReply);
  232.  
  233.         if (sfReply.sfGood == true) {
  234.             *fileToPlay = sfReply.sfFile;
  235.             err = PlaySound (fileToPlay);
  236.         } else {
  237.             err = userCanceledErr;
  238.         }
  239.     }
  240.  
  241.     return err;
  242. }
  243.  
  244. OSErr PlaySound (FSSpec *fileToPlay) {
  245.     OSErr                    err                    = noErr;
  246.     SoundInfo                theSoundInfo;
  247.     SndChannelPtr            soundChan            = nil;
  248.     AudioCompressionAtom    decomAtom;
  249.     SoundComponentData        inputFormat,
  250.                             outputFormat;
  251.     SndCallBackUPP            SoundCallBackFcnUPP    = nil;
  252.     CmpSoundHeader            AIFFSndHeader1,
  253.                             AIFFSndHeader2;
  254.     CmpSoundHeaderPtr        AIFFSndHeader        = nil;
  255.     short                    whichBuffer            = 0;
  256.     SndCommand                playCmd1,
  257.                             playCmd2,
  258.                             callCmd;
  259.     SndCommand*                playCmd                = nil;
  260.     SoundConverter            sc                    = nil;
  261.     Ptr                        decomBuf1            = nil,
  262.                             decomBuf2            = nil,
  263.                             AIFFBuffer            = nil,
  264.                             compressedBuf        = nil,
  265.                             decomBuf            = nil;
  266.     long                    length                = 0;
  267.     unsigned long            inputFrames            = 0,
  268.                             inputBytes            = 0,
  269.                             outputFrames        = 0,
  270.                             outputBytes            = 0,
  271.                             bytesConverted        = 0,
  272.                             targetBytes            = 32768;
  273.     Boolean                    soundDone            = false;
  274.  
  275.     if (err == noErr) {
  276.         err = FSpOpenDF (fileToPlay, fsRdPerm, &theSoundInfo.refNum);
  277.  
  278.         if (err == noErr) {
  279.             err = ASoundGetAIFFHeader (&theSoundInfo, &length, &(decomAtom.formatData));
  280.         }
  281.  
  282.         if (err == noErr) {
  283.             inputFormat.flags = 0;
  284.             inputFormat.format = decomAtom.formatData.format;
  285.             inputFormat.numChannels = theSoundInfo.doubleHeader.dbhNumChannels;
  286.             inputFormat.sampleSize = theSoundInfo.doubleHeader.dbhSampleSize;
  287.             inputFormat.sampleRate = theSoundInfo.doubleHeader.dbhSampleRate;
  288.             inputFormat.sampleCount = 0;
  289.             inputFormat.buffer = nil;
  290.             inputFormat.reserved = 0;
  291.  
  292.             outputFormat.flags = 0;
  293.             outputFormat.format = kSoundNotCompressed;
  294.             outputFormat.numChannels = inputFormat.numChannels;
  295.             outputFormat.sampleSize = inputFormat.sampleSize;
  296.             outputFormat.sampleRate = inputFormat.sampleRate;
  297.             outputFormat.sampleCount = 0;
  298.             outputFormat.buffer = nil;
  299.             outputFormat.reserved = 0;
  300.  
  301.             err = SoundConverterOpen (&inputFormat, &outputFormat, &sc);
  302.         }
  303.  
  304.         if (err == noErr) {
  305.             err = SoundConverterSetInfo (sc, siDecompressionParams, &decomAtom);
  306.         }
  307.  
  308.         if (err == noErr) {
  309.             do {
  310.                 targetBytes *= 2;
  311.                 err = SoundConverterGetBufferSizes (sc, targetBytes, &inputFrames, &inputBytes, &outputBytes);
  312.             } while (err == notEnoughBufferSpace && targetBytes < (MaxBlock () / 4));
  313.         }
  314.  
  315.         if (err == noErr) {
  316.             AIFFBuffer = NewPtr (length);
  317.             err = MemError ();
  318.         }
  319.  
  320.          if (err == noErr) {
  321.             decomBuf1 = NewPtr (outputBytes);
  322.             err = MemError ();
  323.         }
  324.  
  325.         if (err == noErr) {
  326.             decomBuf2 = NewPtr (outputBytes);
  327.             err = MemError ();
  328.         }
  329.  
  330.         if (err == noErr) {
  331.             compressedBuf = NewPtr (inputBytes);
  332.             err = MemError ();
  333.         }
  334.  
  335.         if (err == noErr) {
  336.             err = SetFPos (theSoundInfo.refNum, fsFromStart, theSoundInfo.dataStart);
  337.         }
  338.  
  339.         if (err == noErr) {
  340.             err = FSRead (theSoundInfo.refNum, &length, AIFFBuffer);
  341.         }
  342.  
  343.         if (err == noErr) {
  344.             BlockMoveData (AIFFBuffer, compressedBuf, inputBytes);
  345.             err = SoundConverterBeginConversion (sc);
  346.         }
  347.  
  348.         if (err == noErr) {
  349.             bytesConverted = 0;
  350.             err = SoundConverterConvertBuffer (sc, compressedBuf, inputFrames, decomBuf1, &outputFrames, &outputBytes);
  351.             bytesConverted += inputBytes;
  352.         }
  353.  
  354.         if (err == noErr) {
  355.             if (bytesConverted + inputBytes > length) {
  356.                 inputBytes = length - bytesConverted;
  357.             }
  358.             BlockMoveData (AIFFBuffer + bytesConverted, compressedBuf, inputBytes);
  359.             err = SoundConverterConvertBuffer (sc, compressedBuf, inputFrames, decomBuf2, &outputFrames, &outputBytes);
  360.             bytesConverted += inputBytes;
  361.         }
  362.  
  363.         if (err == noErr) {
  364.             SoundCallBackFcnUPP = NewSndCallBackProc (SoundCallBackFcn);
  365.             err = SndNewChannel (&soundChan, sampledSynth, 0, SoundCallBackFcnUPP);
  366.         }
  367.  
  368.         if (err == noErr) {
  369.             AIFFSndHeader1.samplePtr = decomBuf1;
  370.             AIFFSndHeader1.numChannels = outputFormat.numChannels;
  371.             AIFFSndHeader1.sampleRate = outputFormat.sampleRate;
  372.             AIFFSndHeader1.loopStart = 0;
  373.             AIFFSndHeader1.loopEnd = 0;
  374.             AIFFSndHeader1.encode = cmpSH;
  375.             AIFFSndHeader1.baseFrequency = kMiddleC;
  376.             AIFFSndHeader1.numFrames = outputFrames;
  377.             AIFFSndHeader1.AIFFSampleRate = 0;        // not used
  378.             AIFFSndHeader1.markerChunk = nil;
  379.             AIFFSndHeader1.format = outputFormat.format;
  380.             AIFFSndHeader1.futureUse2 = 0;
  381.             AIFFSndHeader1.stateVars = nil;
  382.             AIFFSndHeader1.leftOverSamples = nil;
  383.             AIFFSndHeader1.compressionID = fixedCompression;        // even uncompressed sounds use fixedCompression
  384.             AIFFSndHeader1.packetSize = 0;            // the Sound Manager will figure this out for us
  385.             AIFFSndHeader1.snthID = 0;
  386.             AIFFSndHeader1.sampleSize = outputFormat.sampleSize;
  387.             AIFFSndHeader1.sampleArea[0] = 0;        // no samples here because use samplePtr instead
  388.  
  389.             BlockMoveData (&AIFFSndHeader1, &AIFFSndHeader2, sizeof (AIFFSndHeader1));
  390.             AIFFSndHeader2.samplePtr = decomBuf2;            
  391.  
  392.             playCmd1.cmd = bufferCmd;
  393.             playCmd1.param1 = 0;                        // not used, but clear it out anyway just to be safe
  394.             playCmd1.param2 = (long)&AIFFSndHeader1;
  395.  
  396.             playCmd2.cmd = bufferCmd;
  397.             playCmd2.param1 = 0;                        // not used, but clear it out anyway just to be safe
  398.             playCmd2.param2 = (long)&AIFFSndHeader2;
  399.  
  400.             whichBuffer = 1;                            // buffer 1 will be free when callback runs
  401.             callCmd.cmd = callBackCmd;
  402.             callCmd.param2 = SetCurrentA5 ();
  403.  
  404.             soundDone = false;
  405.             gBufferDone = false;
  406.             err = SndDoCommand (soundChan, &playCmd1, true);
  407.         }
  408.  
  409.         if (err == noErr) {
  410.             err = SndDoCommand (soundChan, &callCmd, true);
  411.         }
  412.  
  413.         if (err == noErr) {
  414.             err = SndDoCommand (soundChan, &playCmd2, true);
  415.         }
  416.  
  417.         if (err == noErr) {
  418.             while (!soundDone) {
  419.                 if (gBufferDone == true) {
  420.                     if (whichBuffer == 1) {
  421.                         playCmd = &playCmd1;
  422.                         decomBuf = decomBuf1;
  423.                         AIFFSndHeader = &AIFFSndHeader1;
  424.                         whichBuffer = 2;
  425.                     } else {
  426.                         playCmd = &playCmd2;
  427.                         decomBuf = decomBuf2;
  428.                         AIFFSndHeader = &AIFFSndHeader2;
  429.                         whichBuffer = 1;
  430.                     }
  431.  
  432.                     if (bytesConverted < length) {
  433.                         if (bytesConverted + inputBytes > length) {
  434.                             inputBytes = length - bytesConverted;
  435.                         }
  436.  
  437.                         BlockMoveData (AIFFBuffer + bytesConverted, compressedBuf, inputBytes);
  438.  
  439.                         (void)SoundConverterConvertBuffer (sc, compressedBuf, inputFrames, decomBuf, &outputFrames, &outputBytes);
  440.                         bytesConverted += inputBytes;
  441.                         AIFFSndHeader->numFrames = outputFrames;
  442.  
  443.                         gBufferDone = false;
  444.                         (void)SndDoCommand (soundChan, &callCmd, true);            // Reuse callBackCmd.
  445.                         (void)SndDoCommand (soundChan, playCmd, true);            // Play the next buffer.
  446.                     } else {
  447.                         (void)SoundConverterEndConversion (sc, decomBuf, &outputFrames, &outputBytes);
  448.                         AIFFSndHeader->numFrames = outputFrames;
  449.  
  450.                         (void)SndDoCommand (soundChan, playCmd, true);            // Play the last buffer.
  451.                         soundDone = true;
  452.                     }
  453.                 }
  454.             }
  455.         }
  456.  
  457.         if (sc != nil) {
  458.             err = SoundConverterClose (sc);
  459.         }
  460.  
  461.         if (err == noErr) {
  462.             err = SndDisposeChannel (soundChan, false);    // wait until sounds stops playing before disposing of channel
  463.         }
  464.  
  465.     if (theSoundInfo.refNum)
  466.         FSClose (theSoundInfo.refNum);
  467.     if (SoundCallBackFcnUPP)
  468.         DisposeRoutineDescriptor (SoundCallBackFcnUPP);
  469.     if (decomBuf1)
  470.         DisposePtr (decomBuf1);
  471.     if (decomBuf2)
  472.         DisposePtr (decomBuf2);
  473.     if (AIFFBuffer)
  474.         DisposePtr (AIFFBuffer);
  475.     if (compressedBuf)
  476.         DisposePtr (compressedBuf);
  477.     }
  478.  
  479.     return err;
  480. }
  481.  
  482. OSErr InstallRequiredAppleEvents (void) {
  483.     OSErr        err;
  484.  
  485.     err = AEInstallEventHandler (kCoreEventClass, kAEOpenApplication, NewAEEventHandlerProc (HandleOApp), 0, false);
  486.  
  487.     if (err == noErr)
  488.         err = AEInstallEventHandler (kCoreEventClass, kAEOpenDocuments, NewAEEventHandlerProc (HandleODoc), 0, false);
  489.  
  490.     if (err == noErr)
  491.         err = AEInstallEventHandler (kCoreEventClass, kAEPrintDocuments, NewAEEventHandlerProc (HandlePDoc), 0, false);
  492.  
  493.     if (err == noErr)
  494.         err = AEInstallEventHandler (kCoreEventClass, kAEQuitApplication, NewAEEventHandlerProc (HandleQuit), 0, false);
  495.  
  496.     return err;
  497. }
  498.  
  499. pascal OSErr HandleOApp (AppleEvent *theAppleEvent, AppleEvent *reply, long handlerRefcon) {
  500. #pragma unused (theAppleEvent, reply, handlerRefcon)
  501.  
  502.     return noErr;                /* We're up and running */
  503. }
  504.  
  505. pascal OSErr HandleODoc (AppleEvent *theAppleEvent, AppleEvent *reply, long handlerRefcon) {
  506. #pragma unused (reply, handlerRefcon)
  507.  
  508.     AEDescList            docList;
  509.     OSErr                err;
  510.     long                i                = 1,
  511.                         itemsInList;
  512.     Size                actualSize;
  513.     AEKeyword            keywd;
  514.     DescType            returnedType;
  515.  
  516.     err = AEGetParamDesc (theAppleEvent, keyDirectObject, typeAEList, &docList);
  517.     if (err == noErr) {
  518.         err = AECountItems (&docList, &itemsInList);
  519.     }
  520.  
  521.     if (err == noErr) {
  522.         FSSpecPtr    fileSpecPtr;
  523.  
  524.         do {
  525.             fileSpecPtr = (FSSpecPtr)NewPtr (sizeof (FSSpec));
  526.             err = MemError ();
  527.  
  528.             if (err == noErr) {
  529.                 err = AEGetNthPtr (&docList, i, typeFSS, &keywd, &returnedType, fileSpecPtr, sizeof (FSSpec), &actualSize);
  530.             }
  531.  
  532.             if (err == noErr) {
  533.                 HParamBlockRec        pb;
  534.  
  535.                 pb.fileParam.ioCompletion = nil;
  536.                 pb.fileParam.ioNamePtr = fileSpecPtr->name;
  537.                 pb.fileParam.ioVRefNum = fileSpecPtr->vRefNum;
  538.                 pb.fileParam.ioDirID = fileSpecPtr->parID;
  539.                 pb.fileParam.ioFDirIndex = 0;
  540.  
  541.                 err = PBHGetFInfoSync (&pb);
  542.                 if (err == noErr && pb.fileParam.ioFlFndrInfo.fdType != 'pref') {
  543.                     err = PlaySound (fileSpecPtr);
  544.                     DisposePtr ((Ptr)fileSpecPtr);
  545.                 }
  546.             }
  547.  
  548.             i += 1;
  549.         } while (err == noErr);
  550.  
  551.         // The last time through the loop we allocate a pointer we don't need.
  552.         DisposePtr ((Ptr)fileSpecPtr);
  553.     }
  554.  
  555.     (void)AEDisposeDesc (&docList);
  556.  
  557.     return err;
  558. }
  559.  
  560. pascal OSErr HandlePDoc (AppleEvent *theAppleEvent, AppleEvent *reply, long handlerRefcon) {
  561. #pragma unused (theAppleEvent, reply, handlerRefcon)
  562.  
  563.     return noErr;
  564. }
  565.  
  566. pascal OSErr HandleQuit (AppleEvent *theAppleEvent, AppleEvent *reply, long handlerRefcon) {
  567. #pragma unused (theAppleEvent, reply, handlerRefcon)
  568.  
  569.     gDone = true;
  570.     return noErr;
  571. }
  572.